/**
 * 数组reduce()
 *   语法: reduce(callFun,[initValue])
 *             callFun: (previousValue,currentValue,currentIndex,arr)=>{}
 *             initValue: previousValue初始值(可选参数)
 *
 *        reduce() 方法对数组中的每个元素按序执行一个由您提供的 callFun 函数，
 *               每一次运行 callFun 会将先前的计算结果作为参数传入，最后将其结果汇总为单个返回值。
 *              1. 遍历数组元素
 *              2. 执行函数调用，将callFun函数计算结果作为参数传给previousValue
 *              3. 最后将其结果汇总为单个返回值
 *
 *        两种情况:
 *           initValue是否存在
 *             - yes:
 *                  previousValue 初始值为initValue
 *                  currentValue 初始值为arr[0]
 *                  currentIndex 初始值为0
 *             - no：
 *                 previousValue 初始化为 arr[0]
 *                 currentValue 初始值为 arr[1]
 *                 currentIndex 初始值为 1
 *    应用:
 *         - 求数组所有值的和
 *         - 将二维数组转化为一维
 *         - 计算数组或字符串中每个元素出现的次数
 *         - 数组去重
 *
 *
 */

/**
 * 遍历元素
 *    有初始值情况
 */
 const test1 = () => {
	let arr = [4, 6, 7, 9]
	arr.reduce((previousValue, currentValue, currentIndex) => {
		console.log(`previousValue:${previousValue}, currentValue:${currentValue}, currentIndex:${currentIndex}`)
		return currentValue
	}, 0)
}

/**
 * 遍历元素
 *    无初始值情况
 */
const test2 = () => {
	let arr = [4, 6, 7, 9]
	arr.reduce((previousValue, currentValue, currentIndex) => {
		console.log(`previousValue:${previousValue}, currentValue:${currentValue}, currentIndex:${currentIndex}`)
		return currentValue
	})
}

/**
 * 累加求和
 */
const test3 = () => {
	let arr = [4, 6, 7, 9]
	let sum = arr.reduce((previousValue, currentValue, currentIndex) => {
		console.log(previousValue) //0,4,10,17
		return previousValue + currentValue //4,10,17,26
	}, 0)
	console.log(sum)
}

/**
 * 累加求和
 */
const test4 = () => {
	let arr = [
		{ name: 'jack', score: 98 },
		{ name: 'rose', score: 88 },
		{ name: 'tom', score: 90 },
	]
	//计算总成绩
	let total = arr.reduce((previousValue, currentValue) => currentValue.score + previousValue, 0)
	console.log(total)
}

/**
 * 将二维数组转化为一维
 */
const test5 = () => {
	const arr = [
		[1, 2],
		[3, 4],
		[5, 6],
	]
	const newArr = arr.reduce((previousValue, currentValue) => [...previousValue, ...currentValue], [])
	console.log(newArr)
}

/**
 * 计算数组中每个元素出现的次数
 *   判断元素是否在对象中: 对象[元素]
 *    in语句: 元素 in 对象
 *            
 */
const test6 = () => {
	const str = 'helloworldjavascript'
	const arr = str.split('')
	const obj = arr.reduce(
		(previousValue, currentValue) =>{
			// previousValue[currentValue] ? previousValue[currentValue]++ : (previousValue[currentValue] = 1)
			currentValue in previousValue ? previousValue[currentValue]++ : (previousValue[currentValue] = 1)
			return previousValue
		},{})
	console.log(obj)
}


/**
 * 数组去重
 */
const test7 = ()=>{
	const arr = [1,2,3,1,2,4,5,3]
	const newArr = arr.reduce((previousValue,currentValue)=>{
		if(previousValue.indexOf(currentValue) == -1){
			previousValue.push(currentValue)
		}
		return previousValue
	},[])
	console.log(newArr)
}



/**
 * 检查数据类型
 *  对象Object
 *  数组Array
 *  函数Function
 */
 const test8 = () => {
	// let callback = ()=>{}  // [object Function]
	// let callback = {}      // [object Object]
	// let callback = []      // [object Array]
	// let callback = ''      // [object String]
	// let callback = 0       // [object Number]
	let callback = null // [object Null]
	let value = Object.prototype.toString.call(callback)
	console.log(value)
}

/**
 * 自定义reduce
 */
Array.prototype.myReduce = function (callback, init) {
	//判断callback是否函数
	if (!callback && Object.prototype.toString.call(callback) !== '[object Function]') {
		throw new TypeError('callback is not Function')
	}
	//判断方法调用者是否数组
	if (Object.prototype.toString.call(this) !== '[object Array]') {
		throw new TypeError('not Array')
	}
	//数组不能为空
	if (this.length === 0 && init === undefined) {
		throw new TypeError('Reduce of empty arr with no inital value')
	}
	let index = init === undefined ? 1 : 0 //索引号
	let previousValue = init === undefined ? this[0] : init
	const len = this.length

	//reduce功能: 遍历数组元素,每次执行结果返回给previousValue,循环完返回previousValue
	while (index < len) {
		const currentValue = this[index]
		previousValue = callback(previousValue, currentValue, index, this)
		index++
	}
	return previousValue
}